package com.wanrue.tcc.context;


import com.wanrue.tcc.enums.Role;
import com.wanrue.tcc.enums.Status;
import lombok.Data;
import lombok.extern.log4j.Log4j;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 事务信息
 * Created by changmingxie on 10/26/15.
 */
@Data
@Log4j
public class Transaction implements Serializable {

    private static final long serialVersionUID = 7291423944314337931L;

    private Xid xid;

    private Role role;

    private Status status;

    private Integer count = 0;

    private Integer version = 1;

    private Date createTime = new Date();

    private Date lastUpdateTime = new Date();

    private List<Participant> participants = new ArrayList<Participant>();

    private Map<String, Object> attachments = new ConcurrentHashMap<String, Object>();

    public Transaction() {
    }

    public Transaction(Context context) {
        this.xid = context.getXid();
        this.status = Status.TRYING;
        this.role = Role.PARTICIPANT;
    }

    public Transaction(Role role) {
        this.xid = new Xid();
        this.status = Status.TRYING;
        this.role = role;
    }

    public void commit() {
        //保证参与者汇聚点commit成功该点之后不再commit
        Participant confirm = participants.get(0);
        confirm.commit();
        for (int i = 0; i < participants.size(); i++) {
            if (i > 0) {
                try {
                    participants.get(i).commit();
                } catch (Exception e) {
                    log.debug("参与者commit失败", e);
                }
            }
        }
    }

    public void rollback() {
        if (role == Role.INITIATOR) {
            for (int i = 0; i < participants.size(); i++) {
                if (role == Role.INITIATOR && i > 0) {
                    try {
                        participants.get(i).rollback();
                    } catch (Exception e) {
                        log.debug("参与者rollback失败", e);
                    }
                }
            }
        } else {
            for (Participant participant : participants) {
                try {
                    participant.rollback();
                } catch (Exception e) {
                    log.debug("参与者rollback失败", e);
                }
            }
        }
    }

    public void addParticipant(Participant participant) {
        participants.add(participant);
    }
}
